using System.Reflection;

namespace Oomf
{
    public class Property
    {
        private readonly PropertyInfo propertyInfo;

        public Property(PropertyInfo propertyInfo)
        {
            this.propertyInfo = propertyInfo;
        }

        public void SetField<TSource, TResult>(TSource source, TResult result) where TResult : new()
        {
            FieldInfo sourceField = typeof (TSource).GetField(propertyInfo.Name, OomfBindingFlags.BindingFlags);
            object valueToBeSet = propertyInfo.CanRead ? propertyInfo.GetValue(source, null) : sourceField.GetValue(source);
            FieldInfo destinationField = typeof (TResult).GetField(propertyInfo.Name, OomfBindingFlags.BindingFlags);
            if (destinationField == null) return;
            if (PropertyTypesAreNotSame(destinationField)) return;
            
            destinationField.SetValue(result, valueToBeSet);
        }

        public bool SetProperty<TSource, TResult>(TSource source, TResult result) where TResult : new()
        {
            if (!propertyInfo.CanRead) return false;
            PropertyInfo destinationProperty = typeof (TResult).GetProperty(propertyInfo.Name, OomfBindingFlags.BindingFlags);
            if (destinationProperty == null || !destinationProperty.CanWrite) return false;
            if (PropertyTypesAreNotSame(destinationProperty)) return false;
            
            destinationProperty.SetValue(result, propertyInfo.GetValue(source, null), null);
            return true;
        }

        private bool PropertyTypesAreNotSame(FieldInfo destinationField)
        {
            return !propertyInfo.PropertyType.Equals(destinationField.FieldType);
        }

        private bool PropertyTypesAreNotSame(PropertyInfo destinationProperty)
        {
            return !propertyInfo.PropertyType.Equals(destinationProperty.PropertyType);
        }
    }
}